package com.hup.minicontroller.client.service;

import com.hup.minicontroller.client.model.AppConfig;
import com.hup.minicontroller.client.model.AppState;
import com.hup.minicontroller.client.mvp.IClientHandler;
import com.hup.minicontroller.client.mvp.MainMvp.IMainView;
import com.hup.minicontroller.common.constant.ControlActionConstant.FunctionButton;
import com.hup.minicontroller.common.constant.NetConstant.ConnectType;
import com.hup.minicontroller.common.model.dto.*;
import com.hup.utils.commons.start.SpringContext;
import com.hup.utils.io.netty.NettyTCPClient;
import com.hup.utils.io.netty.NettyTCPClient.ClientCallback;
import com.hup.utils.io.netty.NettyTCPClient.ClientConfig;
import com.hup.utils.io.netty.NettyTCPClient.ConnectState;
import com.hup.utils.io.netty.handler.DataCodecHandler;
import com.hup.utils.io.netty.handler.HeartbeatHandler;
import com.hup.utils.io.netty.handler.HeartbeatHandler.IdleCallback;
import com.hup.utils.io.netty.handler.LoginResponseHandler;
import com.hup.utils.io.netty.handler.dataListener.NetSpeedListener;
import com.hup.utils.io.netty.model.LoginResponsePacket;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.Getter;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Locale;

/**
 * wifi和热点)局域网client
 */
@Log4j2
@Component
public class LanClientService implements IClientHandler {
    private static final String TAG = LanClientService.class.getSimpleName();

    private final AppState appState;
    private final ClientConfig clientConfig;
    private final NettyTCPClient client;
    private final NetSpeedListener netSpeedListener;

    @Getter
    private ConnectType connectType = ConnectType.LAN;

    public LanClientService(AppState appState, DataHandlerService dataHandlerService) {
        this.appState = appState;
        MyClientCallback clientCallback = new MyClientCallback();
        clientConfig = new ClientConfig(clientCallback);
        clientConfig.setConnectTimeout(3000);
        clientConfig.loginHandler(clientCallback)
                .setAddHeartbeat(true, clientCallback)
                .addDataHandler(dataHandlerService);
        client = new NettyTCPClient(clientConfig);
        netSpeedListener = new NetSpeedListener();
        DataCodecHandler.INSTANCE.addDataListener(netSpeedListener);
    }

    @Override
    public void switchClient(boolean isConnect) {
        log.info("isConnect={}", isConnect);
        if (isConnect) {
            AppConfig appConfig = appState.getAppConfig();
            clientConfig.target(appConfig.getLanInputIp(), appConfig.getLanServerPort());
            client.connect();
        } else {
            client.disconnect();
        }
    }

    @Override
    public void onControlConfigChanged() {
        if (client.getConnectState() != ConnectState.CONNECTED) return;
        log.info("");
        client.send(appState.getControlConfig());
    }

    @Override
    public void onFunctionButton(FunctionButton button) {
        if (client.getConnectState() != ConnectState.CONNECTED) return;
        log.info("button={}", button.desc);
        client.send(new FunctionButtonRequest(button.index));
    }

    @Override
    public void onFullScreenTouch(FullScreenTouchRequest fullScreenTouchRequest) {
        if (client.getConnectState() != ConnectState.CONNECTED) return;
        //Log.i(TAG, "onFullScreenTouch: ");
        client.send(fullScreenTouchRequest);
    }

    @Override
    public void onTouchPadTouch(TouchPadTouchRequest touchPadTouch) {
        if (client.getConnectState() != ConnectState.CONNECTED) return;
        //Log.i(TAG, "touchPadTouch: ");
        client.send(touchPadTouch);
    }

    @Override
    public void doTerminate() {
        log.info("");
        client.doTerminate();
    }

    @Override
    public void getSpeedText(StringBuilder sb) {
        if (client.getConnectState() != ConnectState.CONNECTED) return;
        netSpeedListener.updateSpeed();
        sb.append(String.format(Locale.getDefault(), "局域网  发送: %dKB/s, 接收: %dKB/s", netSpeedListener.getSendSpeed(), netSpeedListener.getReceiveSpeed()));
    }

    private class MyClientCallback extends LoginResponseHandler<LoginRequest, LoginResponse> implements ClientCallback, IdleCallback {

        @Override
        public void onConnectResult(boolean success, String host, Integer port, LoginResponsePacket loginResponse) {
            log.info("success={}, host={}, loginResponse={}", success, host, loginResponse);
            if (success) {
                LoginResponse response = (LoginResponse) loginResponse;
                appState.setConnectedType(getConnectType());
                appState.setServerName(response.getServerName());
                appState.setLanServerHost(host);
                ControlConfigDto controlConfig = response.getControlConfig();
                if (controlConfig != null) appState.getControlConfig().apply(controlConfig);
            } else {
                appState.onDisconnect();
            }
            SpringContext.executeIfExist(IMainView.class, iMainView -> iMainView.onConnectResult(loginResponse));
        }

        @Override
        public void onConnectionLost() {
            log.info("");
            appState.onDisconnect();
            SpringContext.executeIfExist(IMainView.class, IMainView::onConnectionLost);
            SpringContext.executeIfExist(LanBroadcastReceiverService.class, s -> s.switchService(true));
            //todo
            //ClientApplication.executeIfExist(BluetoothDeviceService.class, s -> s.switchService(true));
        }

        @Override
        public Class<LoginResponse> getLoginResponseType() {
            return LoginResponse.class;
        }

        @Override
        public LoginRequest getLoginValidData() {
            LoginRequest loginRequest = new LoginRequest();
            String userName = System.getProperties().getProperty("user.name");//用户名
            try {
                String pcName = InetAddress.getLocalHost().getHostName();//计算机名
                loginRequest.setName(pcName + "-" + userName);
            } catch (UnknownHostException e) {
                loginRequest.setName(userName);
            }
            log.info("loginRequest={}", loginRequest);
            return loginRequest;
        }

        @Override
        public void onChannelIdle(ChannelHandlerContext ctx, IdleStateEvent e) {
            log.info("无收到消息={}秒,主动关闭连接", HeartbeatHandler.getReaderIdleTimeSeconds());
            ctx.channel().close();
            SpringContext.executeIfExist(IMainView.class, IMainView::onChannelIdle);
        }
    }

}
